﻿#include "framework.h"
#include <CommCtrl.h>
#include "InputBox.h"
#include "MainWindow.h"
#include "Resource.h"

// 函数声明
static void MainWindow_Delete(MainWindow*);
static void MainWindow_DoModal(MainWindow*);
static void MainWindow_Logon(MainWindow*);
static void MainWindow_OnGameOver(MainWindow*, GameOverReason);
static void MainWindow_OnGameStart(MainWindow*, LPCTSTR);
static void MainWindow_OnGetFindUsersResult(MainWindow*, FindUsersResult*);
static void MainWindow_OnGetInviteRequest(MainWindow*, LPCTSTR);
static void MainWindow_OnGetInviteResult(MainWindow*, LPCTSTR, BOOL);
static void MainWindow_OnGetLogonResult(MainWindow*, BOOL);
static void MainWindow_OnGetRivalName(MainWindow*, LPCTSTR);
static void MainWindow_OnLButtonUp(MainWindow*, int, int);
static void MainWindow_OnMenuItemDefeatClicked(MainWindow*);
static void MainWindow_OnMenuItemFindUsersClicked(MainWindow*);
static void MainWindow_OnMenuItemRestartClicked(MainWindow*);
static void MainWindow_OnRivalQuitGame(MainWindow*, BOOL, LPCTSTR);
static INT_PTR CALLBACK MainWindow_Proc(HWND, UINT, WPARAM, LPARAM);

/**
 * 创建主窗口。
 * @return 主窗口
 */
MainWindow* New_MainWindow() {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    int parts[1] = { GAME_BOARD_WIDTH };

    MainWindow* mainWindow = (MainWindow*)calloc(1, sizeof(MainWindow));

    // 初始化函数
    mainWindow->doModal = MainWindow_DoModal;

    // 初始化数据
    mainWindow->mHandle = CreateDialog(NULL, MAKEINTRESOURCE(IDD_MAIN_WINDOW), NULL, MainWindow_Proc);
    SetWindowLongPtr(mainWindow->mHandle, GWLP_USERDATA, (LONG_PTR)mainWindow);

    // 设置状态栏
    mainWindow->mStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM, NULL, mainWindow->mHandle, 0);
    SendMessage(mainWindow->mStatusBar, SB_SETPARTS, 1, (LPARAM)parts);
    LoadString(NULL, IDS_CURRENT_RIVAL, text, STRING_BUF_LEN);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);

    // 创建对手列表窗口
    mainWindow->mRivalWindow = New_RivalWindow(mainWindow->mHandle);

    // 创建游戏区域
    mainWindow->mGameBoard = New_GameBoard(mainWindow->mHandle, 0, 0, GAME_BOARD_WIDTH, GAME_BOARD_HEIGHT);

    // 创建游戏
    mainWindow->mGame = New_Game(mainWindow->mHandle, mainWindow->mGameBoard->mDrawer, mainWindow->mGameBoard->mHandle);
    if (mainWindow->mGame == NULL) {
        LoadString(NULL, IDS_NETWORK_ERROR, text, STRING_BUF_LEN);
        MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONERROR);
        MainWindow_Delete(mainWindow);
        exit(0);
    }

    // 登录
    MainWindow_Logon(mainWindow);

    return mainWindow;
}

/**
 * 删除主窗口。
 * @param mainWindow    主窗口
 */
static void MainWindow_Delete(MainWindow* mainWindow) {
    if (mainWindow->mGame != NULL) {
        mainWindow->mGame->deleteSelf(mainWindow->mGame);
    }
    mainWindow->mGameBoard->deleteSelf(mainWindow->mGameBoard);
    mainWindow->mRivalWindow->deleteSelf(mainWindow->mRivalWindow);
    DestroyWindow(mainWindow->mStatusBar);
    DestroyWindow(mainWindow->mHandle);
    free(mainWindow);
}

/**
 * 以模态显示窗口。
 * @param mainWindow    主窗口
 */
static void MainWindow_DoModal(MainWindow* mainWindow) {
    MSG msg = { 0 };

    // 显示窗口
    ShowWindow(mainWindow->mHandle, SW_SHOW);

    // 窗口事件循环
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

/**
 * 登录。
 * @param mainWindow    主窗口
 */
void MainWindow_Logon(MainWindow* mainWindow) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    InputBox* inputBox = NULL;

    LoadString(NULL, IDS_INPUT_USERNAME, text, STRING_BUF_LEN);
    inputBox = New_InputBox_String(MAX_USERNAME_LEN, mainWindow->mHandle, text);
    if (inputBox->doModal(inputBox) == IDOK) {
        mainWindow->mGame->logon(mainWindow->mGame, inputBox->mStringValue);
        free(inputBox);
    } else {
        free(inputBox);
        MainWindow_Delete(mainWindow);
        exit(0);
    }
}

/**
 * 游戏结束事件的响应方法。
 * @param mainWindow    主窗口
 * @param reason        结束原因
 */
void MainWindow_OnGameOver(MainWindow* mainWindow, GameOverReason reason) {
    TCHAR text[STRING_BUF_LEN] = { 0 };

    // 设置菜单项
    HMENU menu = GetMenu(mainWindow->mHandle);
    EnableMenuItem(menu, IDC_MENU_ITEM_FIND_RIVAL, MF_ENABLED);
    EnableMenuItem(menu, IDC_MENU_ITEM_DEFEAT, MF_GRAYED);
    EnableMenuItem(menu, IDC_MENU_ITEM_RESTART, MF_ENABLED);

    // 显示提示信息
    switch (reason) {
        case LOST:
            LoadString(NULL, IDS_LOST, text, STRING_BUF_LEN);
            break;
        case RIVAL_ADMIT:
            LoadString(NULL, IDS_RIVAL_ADMIT, text, STRING_BUF_LEN);
            break;
        case SELF_ADMIT:
            LoadString(NULL, IDS_SELF_ADMIT, text, STRING_BUF_LEN);
            break;
        case WON:
            LoadString(NULL, IDS_WON, text, STRING_BUF_LEN);
            break;
    }
    MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONINFORMATION);
}

/**
 * 游戏开始事件的响应方法。
 * @param mainWindow    主窗口
 * @param rivalName     对手的名字
 */
void MainWindow_OnGameStart(MainWindow* mainWindow, LPCTSTR rivalName) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    HMENU menu = GetMenu(mainWindow->mHandle);

    // 隐藏对手列表窗口
    ShowWindow(mainWindow->mRivalWindow->mHandle, SW_HIDE);

    // 设置菜单项
    EnableMenuItem(menu, IDC_MENU_ITEM_FIND_RIVAL, MF_GRAYED);
    EnableMenuItem(menu, IDC_MENU_ITEM_DEFEAT, MF_ENABLED);
    EnableMenuItem(menu, IDC_MENU_ITEM_RESTART, MF_GRAYED);

    // 显示对手的名字
    LoadString(NULL, IDS_CURRENT_RIVAL, text, STRING_BUF_LEN);
    _tcscat_s(text, STRING_BUF_LEN, rivalName);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);
}

/**
 * 得到寻找用户结果事件的响应方法。
 * @param mainWindow    主窗口
 * @param usernameList  结果
 */
void MainWindow_OnGetFindUsersResult(MainWindow* mainWindow, FindUsersResult* result) {
    if (result->mUsernameList[0][0] != '\0') {
        mainWindow->mRivalWindow->setUsernameList(mainWindow->mRivalWindow, result->mUsernameList);
        ShowWindow(mainWindow->mRivalWindow->mHandle, SW_SHOW);
    }
}

/**
 * 得到挑战请求事件的响应方法。
 * @param mainWindow    主窗口
 * @param rivalName     对手的名字
 */
void MainWindow_OnGetInviteRequest(MainWindow* mainWindow, LPCTSTR rivalName) {
    TCHAR question[STRING_BUF_LEN] = { 0 };
    TCHAR tempString[STRING_BUF_LEN] = { 0 };
    BOOL accept = FALSE;

    _tcscpy_s(question, STRING_BUF_LEN, rivalName);
    LoadString(NULL, IDS_INVITE, tempString, STRING_BUF_LEN);
    _tcscat_s(question, STRING_BUF_LEN, tempString);
    accept = MessageBox(mainWindow->mHandle, question, _T(" "), MB_ICONQUESTION | MB_YESNO) == IDYES;
    mainWindow->mGame->acceptInvite(mainWindow->mGame, rivalName, accept);
}

/**
 * 得到挑战结果事件的响应方法。
 * @param mainWindow    主窗口
 * @param rivalName     对手的名字
 * @param accept        接受挑战则为 TRUE，否则为 FALSE
 */
void MainWindow_OnGetInviteResult(MainWindow* mainWindow, LPCTSTR rivalName, BOOL accept) {
    TCHAR information[STRING_BUF_LEN] = { 0 };
    TCHAR tempString[STRING_BUF_LEN] = { 0 };

    _tcscpy_s(information, STRING_BUF_LEN, rivalName);
    if (accept) {
        LoadString(NULL, IDS_ACCEPT, tempString, STRING_BUF_LEN);
    } else {
        LoadString(NULL, IDS_REFUSE, tempString, STRING_BUF_LEN);
    }
    _tcscat_s(information, STRING_BUF_LEN, tempString);
    MessageBox(mainWindow->mHandle, information, _T(" "), MB_ICONINFORMATION);
}

/**
 * 得到登录结果事件的响应方法。
 * @param mainWindow    主窗口
 * @param succeeded     登录结果
 * @return 总是零
 */
void MainWindow_OnGetLogonResult(MainWindow* mainWindow, BOOL succeeded) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    if (succeeded) {
        LoadString(NULL, IDS_LOGON_SUCCEEDED, text, STRING_BUF_LEN);
        MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONINFORMATION);
    } else {
        LoadString(NULL, IDS_LOGON_FAILED, text, STRING_BUF_LEN);
        MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONINFORMATION);
        MainWindow_Logon(mainWindow);
    }
}

/**
 * 获取对手的名字事件的响应方法。
 * @param mainWindow    主窗口
 * @param rivalName     对手的名字
 */
void MainWindow_OnGetRivalName(MainWindow* mainWindow, LPCTSTR rivalName) {
    mainWindow->mGame->invite(mainWindow->mGame, rivalName);
}

/**
 * 单击游戏区域事件的响应方法。
 * @param mainWindow    主窗口
 * @param x, y          鼠标位置
 */
void MainWindow_OnLButtonUp(MainWindow* mainWindow, int x, int y) {
    mainWindow->mGame->onGameBoardClicked(mainWindow->mGame, x, y);
}

/**
 * "认输"菜单项的单击响应方法。
 * @param mainWindow    主窗口
 */
void MainWindow_OnMenuItemDefeatClicked(MainWindow* mainWindow) {
    mainWindow->mGame->defeat(mainWindow->mGame);
}

/**
 * "寻找其它用户"菜单项的单击响应方法。
 * @param mainWindow    主窗口
 */
void MainWindow_OnMenuItemFindUsersClicked(MainWindow* mainWindow) {
    mainWindow->mGame->findUsers(mainWindow->mGame);
}

/**
 * "再来一局"菜单项的单击响应方法。
 * @param mainWindow    主窗口
 */
void MainWindow_OnMenuItemRestartClicked(MainWindow* mainWindow) {
    mainWindow->mGame->restart(mainWindow->mGame);
}

/**
 * 对手退出游戏事件的响应方法。
 * @param mainWindow    主窗口
 * @param escape        对手逃跑则为 TRUE，正常退出则为 FALSE
 * @param rivalName     对手的名字
 */
void MainWindow_OnRivalQuitGame(MainWindow* mainWindow, BOOL escape, LPCTSTR rivalName) {
    TCHAR information[STRING_BUF_LEN] = { 0 };
    TCHAR tempString[STRING_BUF_LEN] = { 0 };
    TCHAR text[STRING_BUF_LEN] = { 0 };

    // 设置菜单项
    HMENU menu = GetMenu(mainWindow->mHandle);
    EnableMenuItem(menu, IDC_MENU_ITEM_FIND_RIVAL, MF_ENABLED);
    EnableMenuItem(menu, IDC_MENU_ITEM_DEFEAT, MF_GRAYED);
    EnableMenuItem(menu, IDC_MENU_ITEM_RESTART, MF_GRAYED);

    // 设置状态栏
    LoadString(NULL, IDS_CURRENT_RIVAL, text, STRING_BUF_LEN);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);

    // 显示提示信息
    _tcscpy_s(information, STRING_BUF_LEN, rivalName);
    if (escape) {
        LoadString(NULL, IDS_RIVAL_ESCAPE, tempString, STRING_BUF_LEN);
    } else {
        LoadString(NULL, IDS_RIVAL_QUIT, tempString, STRING_BUF_LEN);
    }
    _tcscat_s(information, STRING_BUF_LEN, tempString);
    MessageBox(mainWindow->mHandle, information, _T(" "), MB_ICONINFORMATION);
}

/**
 * 窗口过程函数。
 * @param window    窗口
 * @param message   事件标识
 * @param wParam    事件相关信息
 * @param lParam    事件相关信息
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
static INT_PTR CALLBACK MainWindow_Proc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    MainWindow* mainWindow = (MainWindow*)GetWindowLongPtr(window, GWLP_USERDATA);
    WORD id = LOWORD(wParam);
    UNREFERENCED_PARAMETER(lParam);

    switch (message) {
        case UM_GAME_OVER:
            MainWindow_OnGameOver(mainWindow, (GameOverReason)wParam);
            return TRUE;
        case UM_GAME_START:
            MainWindow_OnGameStart(mainWindow, (LPCTSTR)wParam);
            return TRUE;
        case UM_GET_FIND_USERS_RESULT:
            MainWindow_OnGetFindUsersResult(mainWindow, (FindUsersResult*)wParam);
            return TRUE;
        case UM_GET_INVITE_REQUEST:
            MainWindow_OnGetInviteRequest(mainWindow, (LPCTSTR)wParam);
            return TRUE;
        case UM_GET_INVITE_RESULT:
            MainWindow_OnGetInviteResult(mainWindow, (LPCTSTR)wParam, (BOOL)lParam);
            return TRUE;
        case UM_GET_LOGON_RESULT:
            MainWindow_OnGetLogonResult(mainWindow, (BOOL)wParam);
            return TRUE;
        case UM_GET_RIVAL_NAME:
            MainWindow_OnGetRivalName(mainWindow, (LPCTSTR)wParam);
            return TRUE;
        case UM_RIVAL_QUIT_GAME:
            MainWindow_OnRivalQuitGame(mainWindow, (BOOL)wParam, (LPCTSTR)lParam);
            return TRUE;
        case WM_COMMAND:
            switch (id) {
                case IDC_MENU_ITEM_DEFEAT:
                    MainWindow_OnMenuItemDefeatClicked(mainWindow);
                    return TRUE;
                case IDC_MENU_ITEM_FIND_RIVAL:
                    MainWindow_OnMenuItemFindUsersClicked(mainWindow);
                    return TRUE;
                case IDC_MENU_ITEM_RESTART:
                    MainWindow_OnMenuItemRestartClicked(mainWindow);
                    return TRUE;
                case IDCANCEL:
                    MainWindow_Delete(mainWindow);
                    return TRUE;
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return TRUE;
        case WM_LBUTTONUP:
            MainWindow_OnLButtonUp(mainWindow, LOWORD(lParam), HIWORD(lParam));
            return TRUE;
    }
    return FALSE;
}
